﻿using System;
using System.Linq;
using System.Runtime.Serialization;
using JetBrains.Annotations;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Utils;

namespace MugenMvvmToolkit.Models
{
    /// <summary>
    ///     Represents the activation policy of view-model.
    /// </summary>
#if WPF
    [Serializable]
#endif
    [DataContract]
    public class ActivationPolicy : IActivationPolicy
    {
        #region Fields

        /// <summary>
        ///     Gets the default activation policy with values: WithoutView = false; UseParentIocAdapter = true;
        /// </summary>
        public static readonly ActivationPolicy WithViewUseParentIocAdaper = new ActivationPolicy(false, true)
        {
            IsFrozen = true
        };

        /// <summary>
        ///     Gets the activation policy with values: WithoutView = false; UseParentIocAdapter = false;
        /// </summary>
        public static readonly ActivationPolicy WithView = new ActivationPolicy(false, false)
        {
            IsFrozen = true
        };

        /// <summary>
        ///     Gets the activation policy with values: WithoutView = true; UseParentIocAdapter = true;
        /// </summary>
        public static readonly ActivationPolicy WithoutViewUseParentIocAdaper = new ActivationPolicy(true, true)
        {
            IsFrozen = true
        };

        /// <summary>
        ///     Gets the activation policy with values: WithoutView = true; UseParentIocAdapter = false;
        /// </summary>
        public static readonly ActivationPolicy WithoutView = new ActivationPolicy(true, false)
        {
            IsFrozen = true
        };

        private bool _withoutView;
        private bool _useParentIocAdapter;
        private string _viewBindingName;
        private string _viewModelBindingName;
        private IIocParameter[] _iocParameters;
        private ListenType? _listenMode;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="ActivationPolicy" /> class.
        /// </summary>
        public ActivationPolicy([NotNull] IActivationPolicy activationPolicy)
        {
            Should.NotBeNull(activationPolicy, "activationPolicy");
            WithoutViewValue = activationPolicy.WithoutView;
            UseParentIocAdapter = activationPolicy.UseParentIocAdapter;
            ListenMode = activationPolicy.ListenMode;
            ViewBindingName = activationPolicy.ViewBindingName;
            ViewModelBindingName = activationPolicy.ViewModelBindingName;
            IocParameters = activationPolicy.IocParameters == null ? null : activationPolicy.IocParameters.ToArray();
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="ActivationPolicy" /> class.
        /// </summary>
        public ActivationPolicy(bool withoutView, bool useParentIocAdapter)
        {
            WithoutViewValue = withoutView;
            UseParentIocAdapter = useParentIocAdapter;
        }

        #endregion

        #region Implementation of IActivationPolicy

        /// <summary>
        ///     Gets the property which responsible to initialize the view.
        /// </summary>
        bool IActivationPolicy.WithoutView
        {
            get { return WithoutViewValue; }
        }

        /// <summary>
        ///     Gets the property which responsible to initialize the view.
        /// </summary>
        public bool WithoutViewValue
        {
            get { return _withoutView; }
            set
            {
                EnsureNotFrozen();
                _withoutView = value;
            }
        }

        /// <summary>
        ///     Gets the value which responsible to initialize the view model as child.
        /// </summary>
        public bool UseParentIocAdapter
        {
            get { return _useParentIocAdapter; }
            set
            {
                EnsureNotFrozen();
                _useParentIocAdapter = value;
            }
        }

        /// <summary>
        ///     Gets or sets the value that responsible for listen messages in created view model.        
        /// </summary>
        public ListenType? ListenMode
        {
            get { return _listenMode; }
            set
            {
                EnsureNotFrozen();
                _listenMode = value;
            }
        }

        /// <summary>
        ///     Gets the view binding name, if any.
        /// </summary>
        public string ViewBindingName
        {
            get { return _viewBindingName; }
            set
            {
                EnsureNotFrozen();
                _viewBindingName = value;
            }
        }

        /// <summary>
        ///     Gets the name of view model binding, if any.
        /// </summary>
        public string ViewModelBindingName
        {
            get { return _viewModelBindingName; }
            set
            {
                EnsureNotFrozen();
                _viewModelBindingName = value;
            }
        }

        /// <summary>
        ///     Gets the ioc parameters, if any.
        /// </summary>
        public IIocParameter[] IocParameters
        {
            get { return _iocParameters; }
            set
            {
                EnsureNotFrozen();
                _iocParameters = value;
            }
        }

        internal bool IsFrozen { get; set; }

        #endregion

        #region Methods

        private void EnsureNotFrozen()
        {
            if (IsFrozen)
                Thrower.ObjectFrozen("ActivationPolicy");
        }

        /// <summary>
        /// Clones the current <see cref="IActivationPolicy"/>.
        /// </summary>
        /// <returns>An instance of <see cref="IActivationPolicy"/>.</returns>
        public ActivationPolicy Clone()
        {
            return new ActivationPolicy(this);
        }

        /// <summary>
        ///     Creates copy of current instance with specified ioc parameters.
        /// </summary>
        public ActivationPolicy WithIocParameters(params IIocParameter[] parameters)
        {
            return new ActivationPolicy(this) { IocParameters = IocParameters };
        }

        /// <summary>
        ///     Creates copy of current instance with specified view binding name.
        /// </summary>
        public ActivationPolicy WithViewBindingName(string viewName)
        {
            return new ActivationPolicy(this) { ViewBindingName = viewName };
        }

        /// <summary>
        ///     Creates copy of current instance with specified view model binding name.
        /// </summary>
        public ActivationPolicy WithViewModelBindingName(string viewModelName)
        {
            return new ActivationPolicy(this) { ViewModelBindingName = viewModelName };
        }

        /// <summary>
        ///     Creates copy of current instance using specified listen mode.
        ///     <c>OneWay</c> - parent view model listens child view model. <c>TwoWay</c> - parent view model listens child view model and child view model listens parent view model.
        /// </summary>
        public ActivationPolicy WithListenMode(ListenType listenMode)
        {
            return new ActivationPolicy(this) { ListenMode = listenMode };
        }

        #endregion
    }
}